import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.regex.Pattern;

import javax.swing.text.AttributeSet;
import javax.swing.text.Element;
import javax.swing.text.ElementIterator;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;


public class Engine implements Runnable {
	

	boolean stop = false;
	boolean end = false;
	BotConfig _cfg;
	String urlSearchPage;
	public Engine(BotConfig cfg){
		_cfg = cfg;
	}
	
	public void run() {
		try {
			urlSearchPage = _cfg.ConstructSearchURI();
			while(urlSearchPage.length() > 0) {
				ArrayList<String> arrKeys = null;
				ArrayList<ArticleDetails> arrArtic = null;
				
				if(_cfg.getExtLoging()){
					System.out.println("Etap 1...");
				}
				
				arrKeys = getArticleKeys();
				if(_cfg.getExtLoging()){
					//System.out.print("Znalezione klucze: ");				
					//for (String arrKey : arrKeys) {
						//System.out.print(arrKey);
					//}
					System.out.println();
				}
				
				if(_cfg.getExtLoging()){
					System.out.println("Etap 2...");
				}
				if(stop == false)
					arrArtic = getArticle(arrKeys);			
				
				if(_cfg.getExtLoging()){
					System.out.println();
					System.out.println();
					System.out.println();
					
					System.out.print("Znalezione artykuły: ");
					for (ArticleDetails articleDetails : arrArtic) {
						System.out.println(articleDetails.getTitle());
						System.out.println(" -- " + articleDetails.getUrl());
						System.out.println();
						System.out.println();
					}
					System.out.print("\n");
				}
				
				if(_cfg.getExtLoging()){
					System.out.print("Etap 3...");
					System.out.print("\n");
				}
				if(stop == false)
					Saver.Save(arrArtic, _cfg);
			}		
			System.out.println("Koniec!!!");
		} catch (Exception ex) {
			System.err.print(ex.getMessage());
			System.err.print("\n");
			for (StackTraceElement el : ex.getStackTrace()) {
				System.err.print(el.toString());
				System.err.print("\n");
			}
		}
		end = true;
	}
	
	private ArrayList<ArticleDetails> getArticle(ArrayList<String> arrKeys) throws Exception{
		ArrayList<ArticleDetails> arrArtic = new ArrayList<ArticleDetails>();
		
		Pattern patTitle = Pattern.compile("^.*Title: .*$");
		Pattern patKeyWords = Pattern.compile("^.*Keywords:.*$");
		Pattern patAbstract = Pattern.compile("^.*Abstract.*:.*$");
		Pattern patPdf = Pattern.compile("^.*Full.*Text.*$");
		Pattern patData = Pattern.compile("^.*(199)|(200)(201)[0-5].*$");		
		
		for (String arrKey : arrKeys) {
			OutputStreamWriter wr = null;
			InputStream is = null;
		    
		    if(stop)
		    	return arrArtic;
		    
			try
			{
				URL url = new URL(prepareUrl(arrKey));
				//URL url = new URL("file:/F:/java/workspace/IcmBot/Examples/sciserv2.htm");
				URLConnection conn = url.openConnection();
				
				//String data = "ArticleKey=" + arrKey;
				//try
				//{
				//	conn.setDoOutput(true);					
				//	wr = new OutputStreamWriter(conn.getOutputStream());
				//    wr.write(data);
				//    wr.flush();
				//}
				//catch (Exception e) {
				//}
			    
			    is = conn.getInputStream();
			    
			    HTMLEditorKit htmlKit = new HTMLEditorKit();
			    HTMLDocument htmlDoc = (HTMLDocument) htmlKit.createDefaultDocument();
			    htmlDoc.putProperty("IgnoreCharsetDirective", new Boolean(true));
			    htmlKit.read(is, htmlDoc, 0);
			    
			    if(_cfg.getExtLoging()){
			    	FileOutputStream tSt = new FileOutputStream("Search2.html");		    	
			    	htmlKit.write(tSt, htmlDoc, 0, htmlDoc.getLength());
				    tSt.flush();
				    tSt.close();
				}
			    
			    ArticleDetails current = null;			    
			    for (HTMLDocument.Iterator iterator = htmlDoc.getIterator(HTML.Tag.A); iterator != null && iterator.isValid(); iterator.next()) {
			    	
			    	if(stop)
				    	return arrArtic;
			    	
			    	int stIdx = iterator.getStartOffset();
			    	int edIdx = iterator.getEndOffset();
			    	String cont = htmlDoc.getText(stIdx, edIdx -stIdx);
			    	if(patPdf.matcher(cont).find())
		    		{
			    		if(current == null)
				    		current = createNewAD();	
			    		AttributeSet attributes = iterator.getAttributes();
			    		String artUrl = (String) attributes.getAttribute(HTML.Attribute.HREF);
			    		current.setUrl(prepareUrl(artUrl));		
			    		break;
		    		}
			    }
			    
			    ElementIterator ei = new ElementIterator(htmlDoc);
		        Element e;
		        while ((e = ei.current()) != null) {
		        	if(stop)
				    	return arrArtic;
		        	
		        	String cont = null;
		        	if("TR".compareToIgnoreCase(e.getName()) == 0 &&
		        			e.getElementCount() == 2){
		        		Element e1 = e.getElement(0);
		        		Element e2 = e.getElement(1);
		        		if("TD".compareToIgnoreCase(e1.getName()) == 0 &&
		        				"TD".compareToIgnoreCase(e2.getName()) == 0){
		        			
		        			int stIdx = e1.getStartOffset();
					    	int edIdx = e1.getEndOffset();
					    	boolean ok = false;
					    	
					    	if(current.isTitle() && edIdx - stIdx < 63) {
					    		cont = htmlDoc.getText(stIdx, edIdx -stIdx);	
					    		if(patTitle.matcher(cont).find())
					    		{
					    			ok = true;
					    			int stIdx2 = e2.getStartOffset();
							    	int edIdx2 = e2.getEndOffset();
							    	
							    	if(current == null)
							    		current = createNewAD();							    	
							    	current.setTitle(htmlDoc.getText(stIdx2, edIdx2 -stIdx2).trim());
					    		}
					    	}
					    	
					    	
					    	if(ok == false && current.isKeywords() && edIdx - stIdx < 70){
					    		cont = htmlDoc.getText(stIdx, edIdx -stIdx);	
					    		if(patKeyWords.matcher(cont).find())
					    		{
					    			ok = true;
					    			int stIdx2 = e2.getStartOffset();
							    	int edIdx2 = e2.getEndOffset();
							    	
							    	if(current == null)
							    		current = createNewAD();							    	
							    	current.setKeywords(htmlDoc.getText(stIdx2, edIdx2 -stIdx2).trim());
					    		}
					    	}
					    	
					    	if(ok == false && current.isDesc() && edIdx - stIdx < 100){
					    		if(cont == null)
					    			cont = htmlDoc.getText(stIdx, edIdx -stIdx);
					    		if(patAbstract.matcher(cont).find())
					    		{
					    			ok = true;
					    			int stIdx2 = e2.getStartOffset();
							    	int edIdx2 = e2.getEndOffset();
							    	
							    	if(current == null)
							    		current = createNewAD();
							    	current.setDesc(htmlDoc.getText(stIdx2, edIdx2 -stIdx2).trim());
					    		}
					    	}
					    	
					    	if(ok == false && edIdx - stIdx < 300){
					    		if(cont == null)
					    			cont = htmlDoc.getText(stIdx, edIdx -stIdx);
					    		if(patData.matcher(cont).find())
					    		{
					    			ok = true;
					    			String[] conts = cont.split(",");
							    	
							    	if(current == null)
							    		current = createNewAD();
							    	current.setYear(conts[conts.length-1].trim());
					    		}
					    	}
		        		}		        		
		        	}
		        	
		            ei.next();
		        }
		        if(current != null)
		    		arrArtic.add(current);
			}
			finally
			{
				if(wr != null)
					wr.close();
				if(is != null)
		    		is.close();
			}
		}
		
		return arrArtic;
	}
	
	private ArrayList<String> getArticleKeys() throws Exception{
		ArrayList<String> arrKeys = new ArrayList<String>();
		InputStream is = null;
	    
	    Pattern contPat = Pattern.compile("^.*Bibliographic Page.*$");
	    Pattern nxtPat = Pattern.compile("^.*next page.*$");
		
	    try
	    {
		    URL url = new URL(prepareUrl(urlSearchPage));
		    URLConnection conn = url.openConnection();
		    
		    urlSearchPage = "";
		    is = conn.getInputStream();
		    
		    HTMLEditorKit htmlKit = new HTMLEditorKit();
		    HTMLDocument htmlDoc = (HTMLDocument) htmlKit.createDefaultDocument();
		    htmlDoc.putProperty("IgnoreCharsetDirective", new Boolean(true));
		    htmlKit.read(is, htmlDoc, 0);
		    		    
		    if(_cfg.getExtLoging()){
		    	FileOutputStream tSt = new FileOutputStream("Search1.html");		    	
		    	htmlKit.write(tSt, htmlDoc, 0, htmlDoc.getLength());
			    tSt.flush();
			    tSt.close();
			}
		    
		    for (HTMLDocument.Iterator iterator = htmlDoc.getIterator(HTML.Tag.A); iterator != null && iterator.isValid(); iterator.next()) {		    	
		    	if(stop)
			    	return arrKeys;
		    	
		    	int stIdx = iterator.getStartOffset();
		    	int edIdx = iterator.getEndOffset();
		    	String cont = htmlDoc.getText(stIdx, edIdx -stIdx);
		    	if(contPat.matcher(cont).find()) {	    		
		    		AttributeSet attributes = iterator.getAttributes();
		    		arrKeys.add((String) attributes.getAttribute(HTML.Attribute.HREF));					    	
	    		}
		    	else if(nxtPat.matcher(cont).find()) {	    		
		    		AttributeSet attributes = iterator.getAttributes();
		    		urlSearchPage = (String) attributes.getAttribute(HTML.Attribute.HREF);					    	
	    		}
		    }	    
		}
	    finally
	    {
	    	if(is != null)
	    		is.close();
	    }
	    return arrKeys;
	}
	
	public void stop(){
		stop = true;
	}

	public boolean isEnd() {
		return end;
	}

	private ArticleDetails createNewAD(){
		ArticleDetails ad = new ArticleDetails();
		ad.setYear(_cfg.getSearchToYear());
		return ad;
	}
	
	private String prepareUrl(String url){
		if(url.startsWith("/")){
			String urlBase = _cfg.getUrlBase();
			for(int i = 0;i<urlBase.length();++i) {				
				if(url.startsWith(urlBase.substring(i))){
					return urlBase.substring(0, i) + url;
				}
			}
		}
		return url;
	}
	
}
